package com.oa.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oa.dao.ApplicationDao;
import com.oa.dao.ApproveInfoDao;
import com.oa.dao.TemplateDao;
import com.oa.entity.Application;
import com.oa.entity.ApplicationVariable;
import com.oa.entity.ApproveInfo;
import com.oa.entity.Template;
import com.oa.entity.User;
import com.oa.service.ApplicationService;
import com.oa.util.UploadUtil;

/**
 * @author FengMengHuo
 * 这个是 申请服务类的实现
 */
@SuppressWarnings("unused")
@Service("applicationService")
@Transactional
public class ApplicationServiceImpl implements ApplicationService {

	@Resource(name="applicationDao")
	private ApplicationDao applicationDao;   //申请

	@Resource(name="approveInfoDao")
	private ApproveInfoDao approveInfoDao;   //审核
	
	@Resource(name="templateDao")
	private TemplateDao templateDao;   //申请模板
	
	@Resource(name="processEngine")
	private ProcessEngine processEngine; //流程引擎
	
	//提交申请模板
	public void addApplication(Application application) {
		//先上传附件，然后再保存申请信息
		Application application1 = this.applicationEntity(application);
		
		applicationDao.saveEntity(application1);
		
		//启动流程实例，按照流程定义的key启动，同时设置流程变量，用于对信息的传递，流程变量的ApplicationVariable不能再随意修改
		Map<String, ApplicationVariable> variables = new HashMap<String, ApplicationVariable>();
		//在jpdl.xml中<task assignee="#{application.applicationLogonName}" g="173,106,127,64" name="提交申请">
		ApplicationVariable applicationVariable = this.applicationPOToVariable(application1);
		variables.put("application", applicationVariable);
		ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey(application1.getProcessDefinitionKey(),variables);
		//完成我的个人任务
		//查找我的个人任务
		Task task = processEngine.getTaskService()//
		               .createTaskQuery()//
		               .processInstanceId(pi.getId())//按照流程实例ID进行查询，获取唯一的Task对象
		               .uniqueResult();
		processEngine.getTaskService().completeTask(task.getId());//使用任务ID完成任务
	}
	
	/**将持久的对象转换成流程变量存储的值*/
	private ApplicationVariable applicationPOToVariable(Application application) {
		ApplicationVariable applicationVariable = new ApplicationVariable();
		//用于javabean属性值的拷贝
		try {
			//左边 为源对象，右边是目标对象
			BeanUtils.copyProperties(application,applicationVariable);
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return applicationVariable;
	}
	
	/**组织持久对象， 用于保存*/
	private Application applicationEntity(Application application) {
		//申请时间
		application.setApplyTime(new Date());
		//申请状态(设置为审核中)
		application.setStatus(Application.APP_RUNNING);
		//使用session获取当前人信息，作为申请的信息(申请人ID，申请人的登录名，申请人的姓名)
		HttpSession session = ServletActionContext.getRequest().getSession();
		User user = (User) session.getAttribute("user1");
		application.setApplicationUserID(user.getUnique_id());
		application.setApplicationLogonName(user.getUser_loginName());
		application.setApplicationUserName(user.getUser_name());
		//申请的标题：申请标题的格式：申请文件模板名称_申请人姓名_申请时间。
		//获取申请模板名称
		Template template = templateDao.getEntity(application.getApplicationTemplateID());
		application.setTitle(template.getTemplate_name()+"_"+user.getUser_name()+"_"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(application.getApplyTime()));
		
		//设置上传的路径，同时上传文件
		application.setUploadPath(UploadUtil.getPath(application.getUpload()));
		//设置流程定义的key
		application.setProcessDefinitionKey(template.getProcessKey());
		return application;
	}

	//查看个人的申请信息
	public List<Application> findApplicationList(Application application) {
		List<Application> applicationList = applicationDao.findAllEntity();
//		public static String APP_RUNNING = "1";  //审核中
//		public static String APP_REJECT = "2";   //审核不通过
//		public static String APP_PASS = "3";     //审核通过
		/*for (Application application2 : applicationList) {
			if("1".equals(application2.getStatus())){
				application2.setStatus("审核中");
			}else if("2".equals(application2.getStatus())){
				application2.setStatus("审核不通过");
			}else{
				application2.setStatus("审核通过");
			}
		}*/
		return applicationList;
	}

	// 待我审批
	public List<Application> findApplicationVariable() {
		//从session中获取当前人的登录名
		User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user1");
		System.out.println(user+"这是user++");
		String logonName = user.getUser_loginName();
		//以登录名做为条件查询任务列表
		List<Task> list = processEngine.getTaskService()//
				         .createTaskQuery()//
				         .assignee(logonName)//指定办理人
				         .list();
		System.out.println(list.size()+"list大小是》》》》");
		//从Task对象中获取对应传递流程变量的对象
		List<Application> applicationList = this.taskListToApplicationList(list);
		return applicationList;
	}
	
	/**从Task对象中获取对应传递流程变量的对象*/
	private List<Application> taskListToApplicationList(List<Task> list) {
		List<Application> applicationList = new ArrayList<Application>();
		if(list!=null){
			for(Task task:list){
				System.out.println("任务ID是》》》》"+task.getId());
				ApplicationVariable applicationVariable = (ApplicationVariable) processEngine.getTaskService()//
				                                             .getVariable(task.getId(), "application");
				Application elecApplication = new Application();
				try {
					BeanUtils.copyProperties(applicationVariable,elecApplication);
				} catch (Exception e) {
					e.printStackTrace();
				} 
				elecApplication.setTaskID(task.getId());
				//处理日期转换
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String applyTime = simpleDateFormat.format(elecApplication.getApplyTime());
				elecApplication.setTime(applyTime);
				applicationList.add(elecApplication);
			}			
		}
		return applicationList;
	}
	// 待我审批
	public Collection<String> getOutComeTransition(
			Application application) {
		//任务ID
		String taskID = application.getTaskID();
		//获取执行连线的名称集合
		Collection<String> collection = processEngine.getTaskService()//
		                           .getOutcomes(taskID);
		return collection;
	}
	// 下载申请文件
	public InputStream findInputStreamByPath(Application application) {
		//获取申请ID
		String id = application.getUnique_id();
		//使用id获取申请的详细信息
		Application application1 = applicationDao.getEntity(id);
		InputStream inputStream = null;
		try {
			//获取路径path
			String path = application1.getUploadPath();
			//获取的标题用作下载文件的名称
			String filename = application1.getTitle();
			//将filename转成iso8859-1的形式，用作在xml
			filename = new String(filename.getBytes("GBK"),"iso8859-1");
			//将filename使用request传递给struts.xml，用来对下载文件的命名
			ServletActionContext.getRequest().setAttribute("fileName", filename);
			//使用路径path找到对应的文件
			File file = new File(path);
			inputStream = new FileInputStream(file);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return inputStream;
	}
	
	//审批处理
	public void approveInfo(Application application) {
		//从页面中获取保存的参数，保存审批信息表
		ApproveInfo approveInfo = this.approveVOToPO(application);
		approveInfoDao.saveEntity(approveInfo);
		
		//按照指定的连线，完成当前任务
		String taskID = application.getTaskID();
		String outcome = application.getOutcome();
		//以任务ID作为条件获取任务对象，而且获取任务对象一定要放置到完成任务前操作
		Task task = processEngine.getTaskService()//
		                 .getTask(taskID);
		processEngine.getTaskService()//
		                      .completeTask(taskID, outcome);
		
		//判断当前流程是否结束
		/**
		 * 如果pi==null：说明流程已经执行完成，该流程已经结束
		 * 如果pi!=null:说明流程没有执行完成，该流程没有结束
		 */
		ProcessInstance pi = processEngine.getExecutionService().findProcessInstanceById(task.getExecutionId());
		
		//根据申请主键ID获取申请的详细信息，用于对审核状态进行更新
		Application application1 = applicationDao.getEntity(application.getUnique_id());
		
		//获取审核人选择的同意或者是不同意的标识
		boolean approval = application.isApproval();
		/**
		 * 判断当前流程是否结束，如果当前流程结束，说明此时审核人审核的信息是最后一个，
         *      * 修改申请状态为“审核通过”
         */
		if(approval){
			if(pi==null){
				application1.setStatus(Application.APP_PASS);
			}
		}
		/**
		 * * 判断当前流程是否结束，如果当前流程没有结束，说明此时审核人审核的信息不是最后一个人，
              * 强制终止流程
              * 修改审核状态为“审核不通过”
		 */
		else{
			if(pi!=null){
				//强制终止流程
				processEngine.getExecutionService().endProcessInstance(pi.getId(), ProcessInstance.STATE_ENDED);
			}
			// 修改审核状态为“审核不通过”
			application1.setStatus(Application.APP_REJECT);
		}
		//elecApplicationDao.update(application);
	}
	/**值转换，从模型驱动中的值转换成保存审批信息*/
	private ApproveInfo approveVOToPO(Application application) {
		ApproveInfo approveInfo = new ApproveInfo();
		
		approveInfo.setApproval(application.isApproval());//是否同意
		approveInfo.setComments(application.getComment());//审批意见
		approveInfo.setApplicationID(application.getUnique_id());//申请ID
		
		User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user1");
		approveInfo.setApproveUserID(user.getUnique_id());   //用户ID
		approveInfo.setApproveUserName(user.getUser_name()); //用户名
		approveInfo.setApproveTime(new Date());        //审批日期（当前日期）
		return approveInfo;
	}
	
	//审批历史
	public List<ApproveInfo> findApproveInfoListByApplicationID(
			Application application) {
		/*String condition = "";
		List<Object> paramsList = new ArrayList<Object>();
		if(application.getUnique_id()!=null){
			condition += " and o.applicationID = ?";
			paramsList.add(application.getUnique_id());
		}
		
		Object [] params = paramsList.toArray();
		LinkedHashMap<String, String> orderby = new LinkedHashMap<String, String>();
		orderby.put("o.approveTime", "asc");*/
		String hql =  "from ApproveInfo where applicationID =?";
		List<ApproveInfo> list = approveInfoDao.uniqueResultEntitys(hql, application.getUnique_id());
		return list;
	}

}
